package cn.iocoder.yudao.module.asasc.service.campaign;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignDataPageReqVO;
import cn.iocoder.yudao.module.asasc.controller.admin.campaign.vo.CampaignDataSaveReqVO;
import cn.iocoder.yudao.module.asasc.dal.dataobject.campaign.CampaignDataDO;
import cn.iocoder.yudao.module.asasc.dal.mysql.campaign.CampaignDataMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.asasc.enums.ErrorCodeConstants.CAMPAIGN_DATA_NOT_EXISTS;

/**
 * 广告数据 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class CampaignDataServiceImpl implements CampaignDataService {

    @Resource
    private CampaignDataMapper campaignDataMapper;

    @Override
    public Long createCampaignData(CampaignDataSaveReqVO createReqVO) {
        // 插入
        CampaignDataDO campaignData = BeanUtils.toBean(createReqVO, CampaignDataDO.class);
        if (Objects.isNull(campaignData.getCreator())) {
            campaignData.setCreator("System");
            campaignData.setDeleted(false);
            campaignData.setTenantId(1L);
        }
        campaignDataMapper.insert(campaignData);
        // 返回
        return campaignData.getId();
    }

    @Override
    public void updateCampaignData(CampaignDataSaveReqVO updateReqVO) {
        // 校验存在
        validateCampaignDataExists(updateReqVO.getId());
        // 更新
        CampaignDataDO updateObj = BeanUtils.toBean(updateReqVO, CampaignDataDO.class);
        campaignDataMapper.updateById(updateObj);
    }

    @Override
    public void deleteCampaignData(Long id) {
        // 校验存在
        validateCampaignDataExists(id);
        // 删除
        campaignDataMapper.deleteById(id);
    }

    private void validateCampaignDataExists(Long id) {
        if (campaignDataMapper.selectById(id) == null) {
            throw exception(CAMPAIGN_DATA_NOT_EXISTS);
        }
    }

    @Override
    public CampaignDataDO getCampaignData(Long id) {
        return campaignDataMapper.selectById(id);
    }

    @Override
    public PageResult<CampaignDataDO> getCampaignDataPage(CampaignDataPageReqVO pageReqVO) {
        PageResult<CampaignDataDO> pageResult = campaignDataMapper.selectPageByKey(pageReqVO);
        //需要对里面的数据的点击率、转化率等进行计算
        for (CampaignDataDO cd : pageResult.getList()) {
            BigDecimal taps = cd.getTaps() != null ? BigDecimal.valueOf(cd.getTaps()) : BigDecimal.ZERO;
            BigDecimal impressions = cd.getImpressions() != null ? BigDecimal.valueOf(cd.getImpressions()) : BigDecimal.ZERO;
            BigDecimal installs = cd.getInstalls() != null ? BigDecimal.valueOf(cd.getInstalls()) : BigDecimal.ZERO;
            BigDecimal localSpendAmount = cd.getLocalSpendAmount() != null ? cd.getLocalSpendAmount() : BigDecimal.ZERO;
            BigDecimal ascProceeds = cd.getAscProceeds() != null ? cd.getAscProceeds() : BigDecimal.ZERO;
            BigDecimal ascRefundProceeds = cd.getAscRefundProceeds() != null ? cd.getAscRefundProceeds() : BigDecimal.ZERO;
            BigDecimal ascInstalls = cd.getAscInstalls() != null ? BigDecimal.valueOf(cd.getAscInstalls()) : BigDecimal.ZERO;
            BigDecimal ascTrial = cd.getAscTrial() != null ? BigDecimal.valueOf(cd.getAscTrial()) : BigDecimal.ZERO;

            cd.setTtr(impressions.compareTo(BigDecimal.ZERO) > 0 ? taps.divide(impressions, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            cd.setConversionRate(taps.compareTo(BigDecimal.ZERO) > 0 ? installs.divide(taps, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO);
            cd.setAvgCpaAmount(installs.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(installs, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            cd.setAvgCptAmount(taps.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(taps, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            cd.setTrialRate(ascInstalls.compareTo(BigDecimal.ZERO) > 0 ? ascTrial.divide(ascInstalls, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            cd.setAvgCpmAmount(impressions.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(impressions, 5, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(1000)) : BigDecimal.ZERO);
            cd.setProfit(ascProceeds.subtract(localSpendAmount).add(ascRefundProceeds));
            cd.setNaturallyInstalls(ascInstalls.subtract(installs).intValue());
        }

        //针对当前查询出来的数据 进行求和，添加到最后一行
        if (!pageResult.getList().isEmpty()) {
            CampaignDataDO sumData = new CampaignDataDO();
            for (CampaignDataDO cd : pageResult.getList()) {
                sumData.setLocalSpendAmount((sumData.getLocalSpendAmount() != null ? sumData.getLocalSpendAmount() : BigDecimal.ZERO).add(cd.getLocalSpendAmount() != null ? cd.getLocalSpendAmount() : BigDecimal.ZERO));
                sumData.setImpressions((sumData.getImpressions() != null ? sumData.getImpressions() : 0) + (cd.getImpressions() != null ? cd.getImpressions() : 0));
                sumData.setTaps((sumData.getTaps() != null ? sumData.getTaps() : 0) + (cd.getTaps() != null ? cd.getTaps() : 0));
                sumData.setInstalls((sumData.getInstalls() != null ? sumData.getInstalls() : 0) + (cd.getInstalls() != null ? cd.getInstalls() : 0));
                sumData.setNewDownloads((sumData.getNewDownloads() != null ? sumData.getNewDownloads() : 0) + (cd.getNewDownloads() != null ? cd.getNewDownloads() : 0));
                sumData.setReDownloads((sumData.getReDownloads() != null ? sumData.getReDownloads() : 0) + (cd.getReDownloads() != null ? cd.getReDownloads() : 0));

                sumData.setAscSales((sumData.getAscSales() != null ? sumData.getAscSales() : BigDecimal.ZERO).add(cd.getAscSales() != null ? cd.getAscSales() : BigDecimal.ZERO));
                sumData.setAscProceeds((sumData.getAscProceeds() != null ? sumData.getAscProceeds() : BigDecimal.ZERO).add(cd.getAscProceeds() != null ? cd.getAscProceeds() : BigDecimal.ZERO));
                sumData.setAscRefundSales((sumData.getAscRefundSales() != null ? sumData.getAscRefundSales() : BigDecimal.ZERO).add(cd.getAscRefundSales() != null ? cd.getAscRefundSales() : BigDecimal.ZERO));
                sumData.setAscRefundProceeds((sumData.getAscRefundProceeds() != null ? sumData.getAscRefundProceeds() : BigDecimal.ZERO).add(cd.getAscRefundProceeds() != null ? cd.getAscRefundProceeds() : BigDecimal.ZERO));
                sumData.setAscImpressions((sumData.getAscImpressions() != null ? sumData.getAscImpressions() : 0) + (cd.getAscImpressions() != null ? cd.getAscImpressions() : 0));
                sumData.setAscTaps((sumData.getAscTaps() != null ? sumData.getAscTaps() : 0) + (cd.getAscTaps() != null ? cd.getAscTaps() : 0));
                sumData.setAscInstalls((sumData.getAscInstalls() != null ? sumData.getAscInstalls() : 0) + (cd.getAscInstalls() != null ? cd.getAscInstalls() : 0));
                sumData.setAscReInstalls((sumData.getAscReInstalls() != null ? sumData.getAscReInstalls() : 0) + (cd.getAscReInstalls() != null ? cd.getAscReInstalls() : 0));
                sumData.setAscUptInstalls((sumData.getAscUptInstalls() != null ? sumData.getAscUptInstalls() : 0) + (cd.getAscUptInstalls() != null ? cd.getAscUptInstalls() : 0));
                sumData.setAscTrial((sumData.getAscTrial() != null ? sumData.getAscTrial() : 0) + (cd.getAscTrial() != null ? cd.getAscTrial() : 0));
                sumData.setAscRenewal((sumData.getAscRenewal() != null ? sumData.getAscRenewal() : 0) + (cd.getAscRenewal() != null ? cd.getAscRenewal() : 0));
                sumData.setAscRefund((sumData.getAscRefund() != null ? sumData.getAscRefund() : 0) + (cd.getAscRefund() != null ? cd.getAscRefund() : 0));
                sumData.setProfit((sumData.getProfit() != null ? sumData.getProfit() : BigDecimal.ZERO).add(cd.getProfit() != null ? cd.getProfit() : BigDecimal.ZERO));
                sumData.setNaturallyInstalls((sumData.getNaturallyInstalls() != null ? sumData.getNaturallyInstalls() : 0) + (cd.getNaturallyInstalls() != null ? cd.getNaturallyInstalls() : 0));
            }
            BigDecimal installs = sumData.getInstalls() != null ? BigDecimal.valueOf(sumData.getInstalls()) : BigDecimal.ZERO;
            BigDecimal taps = sumData.getTaps() != null ? BigDecimal.valueOf(sumData.getTaps()) : BigDecimal.ZERO;
            BigDecimal impressions = sumData.getImpressions() != null ? BigDecimal.valueOf(sumData.getImpressions()) : BigDecimal.ZERO;
            BigDecimal localSpendAmount = sumData.getLocalSpendAmount() != null ? sumData.getLocalSpendAmount() : BigDecimal.ZERO;
            BigDecimal ascTaps = sumData.getAscTaps() != null ? BigDecimal.valueOf(sumData.getAscTaps()) : BigDecimal.ZERO;
            BigDecimal ascImpressions = sumData.getAscImpressions() != null ? BigDecimal.valueOf(sumData.getAscImpressions()) : BigDecimal.ZERO;
            BigDecimal ascInstalls = sumData.getAscInstalls() != null ? BigDecimal.valueOf(sumData.getAscInstalls()) : BigDecimal.ZERO;
            BigDecimal ascTrial = sumData.getAscTrial() != null ? BigDecimal.valueOf(sumData.getAscTrial()) : BigDecimal.ZERO;

            sumData.setConversionRate(taps.compareTo(BigDecimal.ZERO) > 0 ? installs.divide(taps, 4, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setTtr(impressions.compareTo(BigDecimal.ZERO) > 0 ? taps.divide(impressions, 4, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setAvgCpaAmount(installs.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(installs, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setAvgCptAmount(taps.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(taps, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setAvgCptAmount(taps.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(taps, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setTrialRate(ascTrial.compareTo(BigDecimal.ZERO) > 0 ? ascTrial.divide(ascInstalls, 2, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setAvgCpmAmount(impressions.compareTo(BigDecimal.ZERO) > 0 ? localSpendAmount.divide(impressions, 5, RoundingMode.DOWN).multiply(BigDecimal.valueOf(1000)) : BigDecimal.ZERO);
            sumData.setAscTtr(ascImpressions.compareTo(BigDecimal.ZERO) > 0 ? ascTaps.divide(ascImpressions, 4, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setAscConversionRate(ascTaps.compareTo(BigDecimal.ZERO) > 0 ? ascInstalls.divide(ascTaps, 4, RoundingMode.DOWN) : BigDecimal.ZERO);
            sumData.setNaturallyInstalls(ascInstalls.subtract(installs).intValue());

            pageResult.getList().add(sumData);
        }
        return pageResult;
    }

    @Override
    public Map<String, Integer> updateOrSaveCampaignDataByKey(CampaignDataSaveReqVO updateReqVO) {
        CampaignDataDO updateObj = BeanUtils.toBean(updateReqVO, CampaignDataDO.class);
        int insertCount = 0, updateCount = 0;
        Map<String, Integer> result = new HashMap<>();
        try {
            List<CampaignDataDO> campaigns = campaignDataMapper.selectListByKey(updateObj.getAdamId(), updateObj.getDate(), updateObj.getCountryOrRegion());
            if (campaigns.isEmpty()) {
                // 有订阅数据没有广告数据，直接新增
                campaignDataMapper.insert(updateObj);
                insertCount++;
                // log.info("Insert successful for: {}", updateObj.getDate() + "," + updateObj.getCountryOrRegion() + "," + updateObj .getAdamId());
            } else if (campaigns.size() == 1) {
                campaignDataMapper.updateCampaignDataByKey(updateObj);
                updateCount++;
            } else {
                //多个广告系列的情况，找一个广告系列的数据绑定上去，找campaignDataDOS里 安装次数最多的
                CampaignDataDO maxInstalls = campaigns.stream().max(Comparator.comparing(CampaignDataDO::getInstalls)).get();
                updateObj.setCampaignId(maxInstalls.getCampaignId());
                campaignDataMapper.updateCampaignDataByKey(updateObj);
                updateCount++;
            }

            //log.info("updateOrSaveCampaignDataByKey insertCount: {}, updateCount: {}", insertCount, updateCount);
        } catch (Exception e) {
            log.error("updateOrSaveCampaignDataByKey failed: {}", e.getMessage());
        }
        result.put("insertCount", insertCount);
        result.put("updateCount", updateCount);
        return result;
    }

}